package plgbase

import (
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"reflect"
)

/*
**

	SyncMap
*/
type InnerSyncMap struct {
	ownerPlug     interface{}
	innerlst      utils.GSyncMapGroup
	objdna        uint32
	TypeStr       string
	plug          interface{}
	plugID        string
	confIsChanged bool // 最后一次是否改变
	ReleaseFlag   int
}

func NewInnerSyncMap() *InnerSyncMap {
	return &InnerSyncMap{}
}

func NewInnerSyncMap2(owner interface{}) *InnerSyncMap {
	rval := &InnerSyncMap{}
	rval.ConfigOwnerPlug(owner)
	return rval
}

func (this *InnerSyncMap) IsValid() bool {
	return this.plug != nil && this.ReleaseFlag == 0
}

func (this *InnerSyncMap) ConfIsChanged() bool {
	return this.confIsChanged
}

func (this *InnerSyncMap) ConfigOwnerPlug(plg interface{}) {
	this.ownerPlug = plg
}

func (this *InnerSyncMap) Reset() {
	this.plug = nil
	this.plugID = ""
}

func (this *InnerSyncMap) SetInnerPlugId(id string) {
	if this.plugID != id {
		this.plugID = id
		this.plug = nil
	}
}

func (this *InnerSyncMap) Release() {
	this.ownerPlug = nil
	this.innerlst.Clear()
	this.ReleaseFlag = 1
	this.plug = nil
}

func (this *InnerSyncMap) String() string {
	if this.ownerPlug != nil {
		return fmt.Sprintf("%v(%s)-InnerSyncMap", this.ownerPlug, reflect.TypeOf(this.ownerPlug))
	}
	return fmt.Sprintf("%p-InnerSyncMap", this)
}

func (this *InnerSyncMap) StatusString() string {
	if this.plug == nil {
		return fmt.Sprintf("%s(nil)", this.plugID)
	} else {
		return fmt.Sprintf("%s-%s(%p)", this.plugID, reflect.TypeOf(this.plug), this.plug)
	}
}

func (this *InnerSyncMap) SetPlug(val interface{}) {
	this.plug = val
	if val == nil {
		return
	}
}

func (this *InnerSyncMap) CheckDNA() uint32 {
	if this.objdna == 0 {
		this.objdna = utils.NewObjectDNA()
	}
	return this.objdna
}

func (this *InnerSyncMap) LoadOrStore(id interface{}, store interface{}) (actual interface{}, loaded bool) {
	plg := this.checkGetPlug()
	if plg == nil {
		return this.innerlst.LoadOrStore(id, store)
	}

	if smap, ok := plg.(ISyncMap); ok {
		return smap.LoadOrStore(id, store)
	}
	return this.innerlst.LoadOrStore(id, store)
}

func (this *InnerSyncMap) LoadOrStoreDefault(id interface{}, store interface{}, def interface{}) (actual interface{}) {
	plg := this.checkGetPlug()
	if plg == nil {
		return def
	}

	if smap, ok := plg.(ISyncMap); ok {
		actual, _ := smap.LoadOrStore(id, store)
		return actual
	}
	return def
}

func (this *InnerSyncMap) RemoveAndGet(id interface{}) (val interface{}, ok bool) {
	plg := this.checkGetPlug()
	if plg == nil {
		return this.innerlst.RemoveAndGet(id)
	}

	if smap, ok := plg.(ISyncMap); ok {
		return smap.RemoveAndGet(id)
	}
	return this.innerlst.RemoveAndGet(id)
}

func (this *InnerSyncMap) Range(f func(key, value interface{}) bool) {
	plg := this.checkGetPlug()
	if plg == nil {
		this.innerlst.Range(f)
		return
	}
	if smap, ok := plg.(ISyncMapEx); ok {
		smap.Range(f)
		return
	}
	this.innerlst.Range(f)
	return
}

func (this *InnerSyncMap) Set(id interface{}, val interface{}) {
	plg := this.checkGetPlug()
	if plg == nil {
		this.innerlst.Set(id, val)
		return
	}
	if smap, ok := plg.(ISyncMapEx); ok {
		smap.Set(id, val)
		return
	}
	this.innerlst.Set(id, val)
	return
}

func (this *InnerSyncMap) Get(id interface{}, def interface{}) interface{} {
	plg := this.checkGetPlug()
	if plg == nil {
		return this.innerlst.Get(id, def)
	}
	if smap, ok := plg.(ISyncMapEx); ok {
		return smap.Get(id, def)
	}
	return this.innerlst.Get(id, def)
}

func (this *InnerSyncMap) Count() int {
	plg := this.checkGetPlug()
	if plg == nil {
		return this.innerlst.Count()
	}
	if smap, ok := plg.(ISyncMapEx); ok {
		return smap.Count()
	}
	return this.innerlst.Count()
}

/*
*

	{
	    "id":"ex"
	}
*/
func (this *InnerSyncMap) ReloadConf(conf *wrapper.SuperValue) (err error) {

	this.confIsChanged = false
	if conf == nil {
		return
	}

	if conf.IsObject() {
		conf.CheckStrFunc("id", func(strv string) {
			this.SetInnerPlugId(strv)
		})
	} else {
		this.SetInnerPlugId(conf.String())
	}

	return
}

func (this *InnerSyncMap) checkGetPlug() interface{} {
	ex := this.plug
	if ex == nil {
		ex = FindPluginByID(this.plugID)
		if ex != nil {
			this.plug = ex
		}
	}
	return ex
}
